package com.xpec.c4.service.module;

import java.lang.management.ManagementFactory;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;

import javax.management.MBeanServer;
import javax.management.ObjectName;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.jgroups.Address;

import MessageTypes.BasicServiceModuleAction;

import com.ms.game.characterInfo.db.SearchCharacterInfoByDateAsync;
import com.ms.game.common.message.MoudleProcessErrorResponse;
import com.ms.game.common.message.ServerMaintainAction;
import com.ms.game.common.message.ServerReadyAction;
import com.ms.game.gmtool.ServerShutdownType;
import com.ms.game.gmtool.message.SGmtoolKickAllConnectionNotify;
import com.ms.game.gmtool.message.SGmtoolServerShutdownCountdownNotify;
import com.ms.game.log.GameWriteLogAsyncTask;
import com.ms.service.db.jedis.JedisManager;
import com.ms.service.module.account.message.SCharacterLoginNotify;
import com.ms.service.module.commonsettings.CommonSettings;
import com.ms.service.module.datacenterlite.CentralAsyncCommand;
import com.ms.service.module.datacenterlite.DataCenterLiteModule;
import com.ms.service.module.processer.BasiceServiceProcesser;
import com.ms.service.telnet.STelnetCmd;
import com.ms.service.telnet.STelnetCmdResult;
import com.ms.service.telnet.TelGUID;
import com.xpec.c4.codec.CodecUtility;
import com.xpec.c4.db.hibernate.manager.HibernateLogManager;
import com.xpec.c4.db.model.log.basic.BasicLogModel;
import com.xpec.c4.game.cronjob.CreateNewScheduleAsync;
import com.xpec.c4.game.cronjob.CronJobDAO;
import com.xpec.c4.game.cronjob.CronJobManager;
import com.xpec.c4.game.cronjob.CronTaskTimer;
import com.xpec.c4.game.datamanager.CallbackMethodInfo;
import com.xpec.c4.game.datamanager.DataManager;
import com.xpec.c4.game.datamanager.DataProcessAction;
import com.xpec.c4.game.datamanager.DataProcessCallback;
import com.xpec.c4.game.datamanager.DataProcessClassManager;
import com.xpec.c4.game.datamanager.DataRequestInfo;
import com.xpec.c4.game.utility.GUID;
import com.xpec.c4.game.utility.GameUtility;
import com.xpec.c4.message.ConstantCode;
import com.xpec.c4.message.MessageTypes;
import com.xpec.c4.service.common.BaseMessageAction;
import com.xpec.c4.service.common.ModuleInfo;
import com.xpec.c4.service.consistenthash.ConsistentHash;
import com.xpec.c4.service.contexts.Contexts;
import com.xpec.c4.service.contexts.ScopeType;
import com.xpec.c4.service.group.ServerGroup;
import com.xpec.c4.service.group.transportlayer.GroupMessage;
import com.xpec.c4.service.group.transportlayer.SyncModuleInfosMessage;
import com.xpec.c4.service.ioc.IocContainer;
import com.xpec.c4.service.message.MessageAction;
import com.xpec.c4.service.message.NetMessage;
import com.xpec.c4.service.module.async.AsyncProcedureManager;
import com.xpec.c4.service.module.common.PlayerCommonInfoManager;
import com.xpec.c4.service.module.datacenter.DataCenterModule;
import com.xpec.c4.service.module.schedule.ModuleSchedule;
import com.xpec.c4.service.module.task.TaskAsyncCommand;
import com.xpec.c4.service.module.task.TaskNetMessage;
import com.xpec.c4.service.module.task.TaskObject;
import com.xpec.c4.service.module.task.TaskTimer;

/**
 * 
 * 
 * @author lipeilin
 * @2011-3-9 下午04:25:56
 *
 */

public abstract class BasicServiceModule implements IServiceModule, BasicServiceModuleMBean {

	/**
	 * Log管理器
	 */
	private static final Log log = LogFactory.getLog(BasicServiceModule.class);

	/**
	 * module basic processer
	 */
	private BasiceServiceProcesser basicprocesser;

	/**
	 * 子執行緖個數(最少要>=2 ，save log 佔用一條 ， 其他使用一條)
	 */
	public int asyncTaskQueueCount = 16;

	/**
	 * 測試統計效能map
	 */
	// public ConcurrentHashMap<String, MsgExecuteInfo> avgExecuteTimeMap = new
	// ConcurrentHashMap<String, MsgExecuteInfo>();

	/**
	 * 
	 */
	public ObjectName jmxInfoName = null;

	/**
	 * 存放等待處理的Task
	 */
	private Queue<TaskObject> taskQueue = null;
	
	private AtomicInteger taskCounter = new AtomicInteger();

	public int procMsgCount = 0;

	/**
	 * 註冊過的 cron job task
	 */
	private HashSet<CronTaskTimer> registeredCronJobTask = new HashSet<CronTaskTimer>();

	public int getTaskQueueSize() {
//		return taskQueue.size();
		return taskCounter.get();
	}

	public Map<Class, AtomicInteger> getTaskQueueCounter() {
		if (useRecordedQueue)
			return ((RecordedQueue<TaskObject>) taskQueue).getCountingMap();
		else
			return new HashMap<Class, AtomicInteger>();
	}

	public Map<Class, AtomicInteger> getFirstAsyncQueueCounter() {
		return this.asyncProcedureManager.getFirstAsyncQueueCounter();
	}

	private volatile ModuleState state = ModuleState.TestMode;
	
	private volatile ServerShutdownType shutdownType = ServerShutdownType.NONE;

	/**
	 * 唯一的<br>
	 * 這作法只能限制同一個VM只能啟動一個module, 先取消用手動的吧<br>
	 */
	// protected boolean exclusive = false;

	/**
	 * 启动参数
	 */
	protected String[] args;

	/**
	 * 模块名称 (名称跟ID是一起的?)
	 */
	private String moduleName;

	/**
	 * 模块类型
	 * 
	 * @see com.xpec.c4.service.module.ModuleType
	 */
	private int moduleType;

	/**
	 * 主執行緒區間
	 */
	protected ThreadSection mainSection;

	/**
	 * 同步呼叫區間
	 */
	public ThreadSection syncCallSection;

	/**
	 * 消息号与处理类处理函数的映射配置
	 */
	private ModuleInfo moduleInfo = new ModuleInfo();

	/**
	 * 
	 */
	private DataProcessClassManager dataProcessClassInfo = new DataProcessClassManager(this);

	/**
	 * 計時器管理
	 */
	protected ModuleSchedule moduleSchedule = new ModuleSchedule();

	/**
	 * 异步处理器
	 */
	private AsyncProcedureManager asyncProcedureManager = new AsyncProcedureManager(this);

	/**
	 * callback
	 */
	private long snCallback = 0;

	/**
	 * callback method info
	 */
	private Map<Long, CallbackMethodInfo> methodInfoMap = new HashMap<Long, CallbackMethodInfo>();

	/**
	 * 
	 */
	private static final long UPDATE_INFO_PERIOD = 10 * 1000;

	//
	private int maxTaskCount = 0;
	private int showTickCount = 0;

	// static{
	// // 以後再說
	// MessageHandle.setAOP(new MessageMethodInterceptor());
	// }

	private boolean useRecordedQueue = false;
	
	/**
	 * 是否使用兩階段寫入log，預設true
	 */
	private boolean twoStageWriteLog = true;

	public BasicServiceModule() {		
		this(false);
		boolean isFormalServer = ServerProperties.getBoolean(PropertyKey.formal_server, false);
		if(!isFormalServer){
			this.state = ModuleState.RUNNING;
		}
		
		//是否使用兩階段寫入log，預設true
		twoStageWriteLog = ServerProperties.getBoolean(PropertyKey.two_stages_write_log, true);
	}

	/**
	 * 
	 */
	private String serverTestLog = "";

	/**
	 * 依據群組名稱分類，並使用guid做一致性的分配
	 */
	public ConcurrentHashMap<String, ConsistentHash<String>> consistentMap;

	/**
	 * DC Agent Map
	 */
	public ConcurrentHashMap<String, Object> dateCenterAgents;
	
	/**
	 * 共用設定
	 */
	private CommonSettings commonSettings = new CommonSettings();
	
	public CommonSettings getCommonSettings() {
		return commonSettings;
	}

	public void setCommonSettings(CommonSettings commonSettings) {
		this.commonSettings = commonSettings;
	}

	/**
	 * 构造
	 */
	public BasicServiceModule(boolean _useRecordedQueue) {

		useRecordedQueue = _useRecordedQueue;

		taskQueue = useRecordedQueue ? new RecordedQueue<TaskObject>(new ConcurrentLinkedQueue<TaskObject>())
				: new ConcurrentLinkedQueue<TaskObject>();

		mainSection = new ThreadSection(this, taskQueue);
		// 子執行區間以父執行區間為參數初始化
		syncCallSection = new ThreadSection(mainSection, false);
	}

	/**
	 * 参数设置
	 * 
	 * @param args
	 *
	 * @author lipeilin
	 * @2011-3-10 下午12:35:19
	 */
	public void setArguments(String... args) {
		this.args = args;
	}

	/**
	 * 注册消息处理类
	 * 
	 * @param clazz
	 *
	 * @author lipeilin
	 * @2011-3-9 下午04:30:08
	 */
	protected/* static */void registerActionClass(Class<?> clazz) {
		moduleInfo.registerActionClass(clazz);
	}

	// /**
	// * 注册数据处理类
	// * @param dataManager
	// * @param clazz
	// */
	// protected void registerDataProcessActionClass(DataManager<?>
	// dataManager,Class<?> clazz){
	// dataProcessClassInfo.registerActionClass(dataManager, clazz);
	// }

	/**
	 * 
	 * @return
	 */
	public String getModuleName() {
		return moduleName;
	}

	/**
	 * 
	 * @param moduleName
	 */
	public void setModuleName(String moduleName) {
		this.moduleName = moduleName;

	}

	/**
	 * 启动线程
	 */
	public boolean startup() {

		mainSection.createMainThread();

		// 异步处理器
		asyncProcedureManager.startup();

		// 通知Data Center
		// settingDataCenter();

		// show module info计时器
		InfoTaskTimer upd = new InfoTaskTimer();

		upd.setTimerOption(TaskTimer.LOOP);
		upd.setInitialDelay(0);
		upd.setPeriod(UPDATE_INFO_PERIOD);
		upd.setCallback(this);

		addTaskTimer(upd);

		return true;
	}

	/**
	 * 
	 */
	@Override
	public void shutdown() {

		// 结束线程
		state = ModuleState.WAIT_TO_CLOSE;

		// 结束时程
		// sync close
		moduleSchedule.shutdown();

		// 移除 cron job
		ArrayList<CronTaskTimer> cronJobList = new ArrayList<CronTaskTimer>(registeredCronJobTask);
		for (CronTaskTimer cronJob : cronJobList) {
			removeCronTaskTimer(cronJob);
		}

		// 主執行區間
		mainSection.shutdown();

		// async close
		int counter = 0;
		while (!mainSection.isTermineted() && counter < 16) {
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				log.error(e, e);
			}
			counter++;
		}
		mainSection = null;

		if (syncCallSection != null) {
			syncCallSection.shutdown();

			// async close
			counter = 0;
			while (!syncCallSection.isTermineted() && counter < 16) {
				try {
					Thread.sleep(200);
				} catch (InterruptedException e) {
					log.error(e, e);
				}
				counter++;
			}
		}
		syncCallSection = null;

		// 异步处理器
		// sync close
		asyncProcedureManager.shutdown();

		terminated = true;

		if (log.isErrorEnabled()) {
			log.error(moduleName + " shutdown.");
		}
	}

	/**
	 * 
	 */
	@Override
	public void init() {
		
		// 重新改建一個多條线程的异步处理器
		// 因為是在baseModule起始所以要先改變這個數字
		AsyncProcedureManager asyncProcedureManager = this.getAsyncProcedureManager();
		if(asyncProcedureManager != null){
			asyncProcedureManager.setProcedureCount(asyncTaskQueueCount);
		}
				
		
		
		// 默認註冊一個接收資料處理的Action
		registerActionClass(BasicServiceModuleAction.class);
		registerActionClass(DataProcessAction.class);
		registerActionClass(ServerReadyAction.class);
		registerActionClass(ServerMaintainAction.class);

		// 默认建立一条线程的异步处理器
		asyncProcedureManager.createAsyncProcedure(useRecordedQueue);
		JedisManager.initial(moduleName);
	}

	/**
	 * 唤醒线程闲置
	 */
	protected void threadNotify() {
		mainSection.notifyMainThread();
	}

	/**
	 * 進入同步呼叫執行緒區間
	 */
	public void EnterSyncCallSection() {
		syncCallSection.enter();
	}

	/**
	 * 離開同步呼叫執行緒區間
	 */
	public void ExitSyncCallSection() {
		syncCallSection.exit();
	}

	/**
	 * 添加 网路命令到TaskQueue
	 * 
	 * @param messageType
	 * @param messageContentBytes
	 * @param sessionID
	 * @param srcService
	 * @param options
	 * @return
	 */
	public boolean addMessage(int messageType, int syncId, byte[] messageContentBytes, GUID sessionID,
			String srcService, Address srcAddress, int options) {

		// 如果是偵測Message的Request 先回應收到再繼續 (表示網路傳輸是正常的)
		if (messageType == MessageTypes.S_SERVER_TEST_REQUEST) {
			String messageContent = (String) CodecUtility.decodeByte(messageContentBytes);

			serverTestLog += "Get Server Test Request from " + messageContent + " : " + this.getModuleName()
					+ " Time:" + System.currentTimeMillis() + "\n";

			GroupMessage msg = new GroupMessage();
			msg.setDestModuleID(messageContent);
			msg.setMessageType(MessageTypes.S_SERVER_TEST_RESPONSE);
			msg.setMessageContent("2. Get Server Test Request : " + this.getModuleName() + " Time:"
					+ System.currentTimeMillis() + "\n");
			MessageAction.sendMessage(msg);
		}
		//
		else if (messageType == MessageTypes.S_SERVER_TEST_RESPONSE) {
			String messageContent = (String) CodecUtility.decodeByte(messageContentBytes);

			serverTestLog += messageContent;
			serverTestLog += "Get Server Test Response : " + this.getModuleName() + " Time:"
					+ System.currentTimeMillis() + "\n";
		}

		// todo memo
		// 收到网路来的命令
		// MessageHandle 里面有关 HandleMessage内create class 的部份搬进来
		// 堆进queue里面
		// 处理queue (在run内)
		// 网路 有的action 会返回message, 这边还要把message丢回网路

		TaskNetMessage tnm = new TaskNetMessage();

		tnm.setMessageType(messageType);
		tnm.setSyncId(syncId);
		tnm.setMessageContentBytes(messageContentBytes);
		tnm.setSessionID(sessionID);
		tnm.setOptions(options);
		tnm.setSrcService(srcService);
		tnm.setModuleServer(this);
		tnm.setModuleID(this.getModuleName());
		tnm.setSrcAddress(srcAddress);

		// 添加task到queue內
		boolean result = taskQueue.add(tnm);
		//+1
		int taskCount = taskCounter.incrementAndGet();
		// BM test 暫時不顯示 task count log
		
		// 顯示消息堆積的 error log
		if (log.isErrorEnabled()) {
			if (taskCount >= 200 && (taskCount % 100 == 0)) {
				log.error(getModuleName() + " TaskNetMessage taskQueue task count reach " + taskCount);
			}
		}
		

		// 喚醒線程
		threadNotify();

		return result;
	}

	/**
	 * 處理網路信息
	 * 
	 * @param to
	 */
	public void procNetworkMessage(TaskNetMessage to) {

		if (to == null) {
			return;
		}

		int messageType = to.getMessageType();

		// 如果是偵測Message的Request 回應已執行 (表示主執行緒是活著的)
		if (messageType == MessageTypes.S_SERVER_TEST_REQUEST) {

			String messageContent = (String) CodecUtility.decodeByte(to.getMessageContentBytes());

			serverTestLog += "Process Server Test Request from " + messageContent + " : " + this.getModuleName()
					+ " Time:" + System.currentTimeMillis() + "\n";

			GroupMessage msg = new GroupMessage();
			msg.setDestModuleID(messageContent);
			msg.setMessageType(MessageTypes.S_SERVER_TEST_RESPONSE);
			msg.setMessageContent("3.Process Server Test Request : " + this.getModuleName() + " Time:"
					+ System.currentTimeMillis() + "\n");
			MessageAction.sendMessage(msg);
			return;
		} else if (messageType == MessageTypes.S_SERVER_TEST_RESPONSE) {
			// String messageContent =
			// (String)CodecUtility.decodeByte(to.getMessageContentBytes());
			serverTestLog += "Process Server Test Response : " + this.getModuleName() + " Time:"
					+ System.currentTimeMillis() + "\n";
			return;
		}

		// 处理方法
		Method dealAction = moduleInfo.getDealMethod(messageType);

		// 处理类
		Class<?> dealClass = moduleInfo.getDealClazz(messageType);

		if (dealClass == null || dealAction == null) {
			log.warn(ConstantCode.getName(MessageTypes.class, messageType) + " " + messageType
					+ " not mapping deal action!!!");
			return;
		}

		Object messageContent;
		try {
			messageContent = CodecUtility.decodeByte(to.getMessageContentBytes());
		} catch (RuntimeException e1) {
			log.error("cannot decode msg :" + messageType);
			throw e1;
		}

		Contexts.putInContexts("moduleID", to.getModuleID());
		Contexts.putInContexts("srcService", to.getSrcService());
		Contexts.putInContexts("TaskNetMessage", to);

		if (to.getSessionID() != null) {
			Contexts.putSessionIDInEventContext(to.getSessionID());
			Contexts.flushSessionIDUserID();
			Contexts.putInContexts("sessionID", to.getSessionID(), ScopeType.EVENT);
		}

		// 方法前运行
		Object dealObj = IocContainer.createObject(dealClass);

		// 協助proceser設定action參數
		if (basicprocesser != null && dealObj instanceof BaseMessageAction) {
			basicprocesser.setBaseaction((BaseMessageAction) dealObj);
		}

		Object obj = null;
		try {
			try {
				messageContent = CodecUtility.h2oArrayTransfer(to.getMessageContentBytes(), messageContent,
						dealAction.getParameterTypes());

				if (log.isInfoEnabled()) {
					String playerIdStr = "";
					if (to.getSessionID() != null) {
						GUID playerId = PlayerCommonInfoManager.getInstance().getPlayerGuidBySession(
								to.getSessionID());
						if (playerId != null) {
							playerIdStr = " from g:" + playerId;
						}

					}

					if (messageType != MessageTypes.C_PERIOD_SYNC_REQUEST) {
						log.info("recv " + ConstantCode.getName(MessageTypes.class, messageType) + playerIdStr);
					}
				}

				obj = dealAction.invoke(dealObj, messageContent);
			} catch (IllegalArgumentException e) {
				log.error("sessionID:" + (to.getSessionID() != null ? to.getSessionID() : "null")
						+ " message type:" + messageType + " \tmessage object:" + messageContent
						+ " \tmessage method:" + dealAction, e);

				procThrowException(messageContent);

				throw e;
			} catch (RuntimeException e) {
				log.error("sessionID:" + (to.getSessionID() != null ? to.getSessionID() : "null")
						+ " message type:" + messageType + " \tmessage object:" + messageContent
						+ " \tmessage method:" + dealAction, e);

				procThrowException(messageContent);

				throw e;
			} catch (IllegalAccessException e) {
				log.error("sessionID:" + (to.getSessionID() != null ? to.getSessionID() : "null")
						+ " message type:" + messageType + " \tmessage object:" + messageContent
						+ " \tmessage method:" + dealAction, e);
				
				procThrowException(messageContent);
				throw e;
			} catch (InvocationTargetException e) {
				log.error("sessionID:" + (to.getSessionID() != null ? to.getSessionID() : "null")
						+ " message type:" + messageType + " \tmessage object:" + messageContent
						+ " \tmessage method:" + dealAction, e);

				procThrowException(messageContent);

				throw e;
			} catch (Exception e) {
				log.error("sessionID:" + (to.getSessionID() != null ? to.getSessionID() : "null")
						+ " message type:" + messageType + " \tmessage object:" + messageContent
						+ " \tmessage method:" + dealAction, e);

				procThrowException(messageContent);
				throw e;
			}
		} catch (Throwable t) {
			// 為避免對server core的影響,目前logException只應用在mobile module
			if (t instanceof RuntimeException) {
				procThrowException(messageContent);
				throw (RuntimeException) t;
			}
		}

		// 返回消息
		if (to.getSyncId() != 0) {
			// 有同步Id 為server間呼叫
			if (to.getSyncReturn() == true) {
				ServerGroup.getTransportManager().sendResponse(to.getSrcAddress(), to.getSyncId(), obj);
			}
		} else {

			// 不返回对象，或返回是null，则不作任何处理。
			if (obj == null) {

			} else if (obj instanceof NetMessage) {
				// 返回的对象是NetMessage，用于发送一个指定客户端对象

				// 如果sessionID是空，则表示返回原来的session
				if (((NetMessage) obj).getSessionID() == null) {
					((NetMessage) obj).setSessionID(to.getSessionID());
				}
				MessageAction.sendMessage((NetMessage) obj);
			} else if (obj instanceof Collection) {
				// 返回的对象是Collection<NetMessage>，用于发送多个对象
				MessageAction.sendMessage((Collection<NetMessage>) obj);
			} else {
				// 如果是其他类型对象，则无法处理，不管
				if (log.isDebugEnabled()) {
					log.debug("return message is not NetMessage:" + obj);
				}
			}
		}

		// 清除event context
		Contexts.destroyEventContext();
	}

	/**
	 * 移除計時對象
	 * 
	 * @param tObj
	 * @return
	 */
	public boolean removeTaskTimer(TaskTimer tObj) {
		return (tObj != null) ? moduleSchedule.remove(tObj) : false;
	}

	/**
	 * 添加 执行命令 (開始計時)
	 * 
	 * @param tObj
	 * @return
	 */
	public boolean addTaskTimer(TaskTimer tObj) {

		if (tObj.getTimerOption() == TaskTimer.LOOP && tObj.getPeriod() <= 0) {
			return false;
		}

		tObj.setModuleServer(this);
		// 將TaskTimer添加到
		return moduleSchedule.add(tObj);
	}

	public boolean addTaskTimer(TaskTimer tObj, int timerOption, long delay, long period, Object callBack) {
		if (tObj == null)
			return false;
		tObj.setTimerOption(timerOption);
		tObj.setInitialDelay(delay);
		tObj.setPeriod(period);
		tObj.setCallback(this);
		return this.addTaskTimer(tObj);
	}
	
	/**
	 * 新增一個可以指定時間點執行的 timer
	 * 
	 * @param cronTaskTimer
	 *            繼承 {@link CronTaskTimer} 的 task object 實體
	 * @param cronExpressions
	 *            定時執行的時間表示式<br>
	 *            "0 07 16 * * ?" 每天 16:07 執行一次<br>
	 *            "0/10 * * * * ?" 從每分鐘的零秒開始，每10秒執行一次<br>
	 *            "0 32/60 * * * ?" 每小時的 32 分開始，每60分鐘執行一次<br>
	 *            "0 8/10 * * * ?" 每小時的 8 分開始，每10分鐘執行一次<br>
	 *            "0 * * * * ?" 每分鐘執行一次<br>
	 *            產生器: http://www.cronmaker.com/
	 * @return
	 */
	public boolean addCronTaskTimer(CronTaskTimer cronTaskTimer) {
		cronTaskTimer.setModuleServer(this);
		boolean res = CronJobManager.getInstance().registerJob(cronTaskTimer, cronTaskTimer.getCronExpressions());
		if (res) {
			if (!registeredCronJobTask.add(cronTaskTimer)) {
				if (log.isErrorEnabled()) {
					log.error(GameUtility.getCurMethodName() + ": add task "
							+ cronTaskTimer.getClass().getSimpleName() + " to registeredCronJobTask fail.");
				}
			}
		}
		return res;
	}
	
	/**
	 * 移除定時器
	 * 
	 * @param cronTaskTimer
	 *            timer object
	 * @return
	 */
	public boolean removeCronTaskTimer(CronTaskTimer cronTaskTimer) {
		boolean res = CronJobManager.getInstance().unregisterJob(cronTaskTimer);
		if (res) {
			if (!registeredCronJobTask.remove(cronTaskTimer)) {
				if (log.isErrorEnabled()) {
					log.error(GameUtility.getCurMethodName() + ": remove task "
							+ cronTaskTimer.getClass().getSimpleName() + " from registeredCronJobTask fail.");
				}
			}
		}
		return res;
	}

	/**
	 * 添加命令到 TaskQueue
	 * 
	 * @param obj
	 * @return
	 */
	public boolean addTaskObject(TaskObject obj) {
		if (obj == null) {
			return false;
		}

		obj.setModuleServer(this);
		boolean result = taskQueue.add(obj);
		taskCounter.incrementAndGet();
		threadNotify();
		return result;
	}

	// /**
	// * 只给module使用
	// * @return
	// */
	// protected Contexts getContexts() {
	// return contexts;
	// }

	/**
	 * 添加异步Task 不分配
	 * 
	 * @param obj
	 * @return
	 */
	public boolean addAsyncCommand(TaskAsyncCommand obj) {
		if (obj == null) {
			if (log.isErrorEnabled()) {
				GameUtility.logErrorException(log, "obj=null.");
			}
		}

		// 有設定 key 的話自動分配到對應的 queue 去執行
		if (obj != null) {
			if (obj.key != null) {
				obj.setQueueID(guidToAsyncQueueId(obj.key));
			}
		}
		
		
		//20160616 將查詢玩家遊戲log放到第15條thread來做
		if(obj  instanceof SearchCharacterInfoByDateAsync)
		{
			obj.setQueueID(GameUtility.getLastNIndex(asyncTaskQueueCount, 2));
		}
		
		
		// 填入執行時所在的 module
		obj.setCurrentModuleServer(this);
		
		if(obj.getQueueID() == 15 && !(obj instanceof GameWriteLogAsyncTask)){
			if(log.isErrorEnabled()){
				log.error("Using Thread 15 " +  obj.getClass().getName());
			}
		}
		return asyncProcedureManager.addAsyncCommand(obj);
	}

	/**
	 * 將工作送出到 {@link DataCenterLiteModule} 執行，再回到本地執行 callback
	 * 
	 * @param obj
	 *            命令 class
	 * @param userData
	 *            自訂參數，回本地執行 callback 時取用
	 * @return
	 */
	public boolean addCentralAsyncCommand(CentralAsyncCommand obj, Object... userData) {
		if (obj == null) {
			if (log.isErrorEnabled()) {
				GameUtility.logErrorException(log, "obj=null.");
			}
		}

		// 記錄不帶過去的資料，callback回來後使用
		Long snCallback = addDataProcessCallbackAndUserData(null, null, null, null, null, userData);
		obj.setSnCallback(snCallback);
		obj.setModuleID(this.getModuleName());
		
		if (obj.key != null) {
			obj.setQueueID(guidToAsyncQueueId(obj.key));
		}

		GroupMessage msg = new GroupMessage();
		msg.setMessageType(MessageTypes.S_CENTRAL_REQUEST);
		msg.setMessageContent(obj);
		msg.setDestModuleID(ModuleName.DATA_CENTER_LITE);
		MessageAction.sendMessage(msg);

		return true;
	}

	/**
	 * 將工作送出到 {@link DataCenterModule} 執行，再回到本地執行 callback
	 * 
	 * @param obj
	 *            命令 class
	 * @param userData
	 *            自訂參數，回本地執行 callback 時取用
	 * @return
	 */
	public boolean addCentralAsyncCommandToDC(CentralAsyncCommand obj, Object... userData) {
		if (obj == null) {
			if (log.isErrorEnabled()) {
				GameUtility.logErrorException(log, "obj=null.");
			}
		}

		// 記錄不帶過去的資料，callback回來後使用
		Long snCallback = addDataProcessCallbackAndUserData(null, null, null, null, null, userData);
		obj.setSnCallback(snCallback);
		obj.setModuleID(this.getModuleName());
		
		if (obj.key != null) {
			obj.setQueueID(guidToAsyncQueueId(obj.key));
		}

		String destModuleName = null;
		if (obj.key != null) {
			destModuleName = ConsistentGroupName.lookUp(ModuleName.GROUP_DATA_CENTER, obj.key);
			if (!GameUtility.isHaveString(destModuleName)) {
				if (log.isErrorEnabled()) {
					GameUtility.logErrorException(log, "get module name fail.");
				}
				return false;
			}
		} else {
			String firstModuleName = ServerProperties.getFirstModuleName(ModuleName.DATA_CENTER);
			if (!GameUtility.isHaveString(firstModuleName)) {
				if (log.isErrorEnabled()) {
					GameUtility.logErrorException(log, "get first dc module name fail.");
				}
				return false;
			}

			destModuleName = firstModuleName;
		}

		if (log.isInfoEnabled()) {
			log.info("send CentralAsyncCommand to " + destModuleName + ", key=" + obj.key);
		}

		GroupMessage msg = new GroupMessage();
		msg.setMessageType(MessageTypes.S_CENTRAL_REQUEST);
		msg.setMessageContent(obj);
		msg.setDestModuleID(destModuleName);
		MessageAction.sendMessage(msg);

		return true;
	}

	/**
	 * 將 guid 轉成對應的異步處理 queue id
	 * @param key
	 * @param totalQueueCount
	 * @return
	 */
	public int guidToAsyncQueueId(GUID key) {
		if (key == null) {
			return 0;
		}

		int last2Index = GameUtility.getLastNIndex(asyncTaskQueueCount, 2);
		int hash = key.hashCode() % last2Index;
		int queueId = (hash < 0) ? -hash : hash;
		return queueId;
	}

	/**
	 * 
	 * @param moduleType
	 */
	public void setModuleType(int moduleType) {
		this.moduleType = moduleType;
	}

	/**
	 * 
	 * @return
	 */
	public int getModuleType() {
		return moduleType;
	}

	/**
	 * 
	 * @param obj
	 */
	public void dataProcessResponsedispatch(DataRequestInfo obj) {
		// 將回傳的資料送給對應的處理方法
		dataProcessClassInfo.dataProcessResponse(obj.getDataInfo());
	}

	//
	// /**
	// *
	// * @param data
	// */
	// public void testDataProcessResponse(BaseDataInfo data){
	// dataProcessClassInfo.dataProcessResponse(data);
	// }
	//

	public CallbackMethodInfo getCallbackMethodInfoBySn(Long snCallback) {
		return methodInfoMap.get(snCallback);
	}

	/**
	 * 
	 * @param snCallback
	 * @return
	 */
	public boolean removeDataProcessCallbackAndUserDataBySn(Long snCallback) {
		boolean result = (methodInfoMap.remove(snCallback) != null);
		return result;
	}

	/**
	 * 
	 * @param classOfPreProcMethod
	 * @param preProcMethod
	 * @param classOfMethod
	 * @param method
	 * @param callback
	 * @param userData
	 * @return
	 */
	public Long addDataProcessCallbackAndUserData(Object classOfPreProcMethod, Method preProcMethod,
			Object classOfMethod, Method method, DataProcessCallback callback, Object... userData) {

		snCallback++;

		CallbackMethodInfo info = new CallbackMethodInfo();

		info.setClassOfPreProcMethod(classOfPreProcMethod);
		info.setPreProcMethod(preProcMethod);
		info.setCallback(callback);
		info.setClassOfMethod(classOfMethod);
		info.setMethod(method);
		info.setUserData(userData);

		methodInfoMap.put(snCallback, info);
		
		if(log.isInfoEnabled()){
			log.info(GameUtility.getCurMethodName() + " SN = " + String.valueOf(snCallback));
		}
		
		return new Long(snCallback);
	}

	//
	// /**
	// *
	// * @param data
	// * @param callback
	// * @param userData
	// * @return
	// */
	// public boolean settingDataCenter(Object... userData) {
	//
	// GroupMessage msg = new GroupMessage();
	// msg.setMessageType(MessageTypes.S_DATA_SETTING);
	// msg.setMessageContent(this.moduleName);
	// msg.setDestModuleID(ModuleName.DATA_CENTER);
	// MessageAction.sendMessage(msg);
	//
	// return true;
	// }

	/**
	 * 
	 */
	public void dumpBasicInfo() {

		boolean show = false;
		int cnt = taskCounter.get();
		if (cnt > 0) {
			if (cnt > maxTaskCount) {
				maxTaskCount = cnt;
			}
		}

		showTickCount++;

		if ((cnt > 100 || this.asyncProcedureManager.getTaskQueueSize() > 100) && showTickCount > 10) {
			show = true;
			showTickCount = 0;
		} else if (showTickCount > 20) {
			// show = true;
			// showTickCount = 0;
		}

		if (show) {
			log.error("Current TaskCount: " + cnt + " async: " + this.asyncProcedureManager.getTaskQueueSize()
					+ " Max TaskCount: " + maxTaskCount);
		}

	}

	private volatile boolean terminated = false;

	public boolean isTerminated() {
		return terminated;
	}

	// private void logException(Throwable t, Object dealObj,
	// Object messageContent, TaskNetMessage to) {
	// try {
	// String requestId = null;
	// String acctId = null;
	// String guid = null;
	// BaseMessageAction act = null;
	// if(dealObj instanceof BaseMessageAction) {
	// act = (BaseMessageAction)dealObj;
	// acctId = act.getAccountID() == null ? null :
	// GUID.toString(act.getAccountID());
	// guid = act.getPlayerID() == null ? null :
	// GUID.toString(act.getPlayerID());
	// }
	// } catch (Exception e) {
	// log.error("error at logging exception", e);
	// }
	// }

	public AsyncProcedureManager getAsyncProcedureManager() {
		return asyncProcedureManager;
	}

	public void setAsyncProcedureManager(AsyncProcedureManager asyncProcedureManager) {
		this.asyncProcedureManager = asyncProcedureManager;
	}

	public class MsgExecuteInfo {
		public long aveExecuteTime;
		public long callTimes;
	}

	public int getCurrentAsyncTaskCount() {
		return asyncProcedureManager.getCurrentTaskCount();
	}

	@Override
	public Map<String, Integer> getStatistics() {
		return new HashMap<String, Integer>();
	}

	/*
	 * public void updataExecuteCount(String logTitle, long operatorTime){
	 * MsgExecuteInfo info = avgExecuteTimeMap.get(logTitle);
	 * if(info == null){
	 * info = new MsgExecuteInfo();
	 * info.callTimes = 1;
	 * info.aveExecuteTime = operatorTime;
	 * }
	 * else{
	 * info.callTimes++;
	 * info.aveExecuteTime = (info.aveExecuteTime * (info.callTimes -1) +
	 * operatorTime)/info.callTimes;
	 * }
	 * avgExecuteTimeMap.put(logTitle, info);
	 * procMsgCount ++;
	 * if(procMsgCount >= 1000){
	 * procMsgCount = 0;
	 * Iterator<Entry<String ,MsgExecuteInfo>> itr =
	 * avgExecuteTimeMap.entrySet().iterator();
	 * while(itr.hasNext()){
	 * Entry<String ,MsgExecuteInfo> node = itr.next();
	 * log.error("msg avg: " + node.getKey() + ", callTimes:" +
	 * node.getValue().callTimes + ", avg execute Time:" +
	 * node.getValue().aveExecuteTime);
	 * }
	 * }
	 * }
	 */

	/**
	 * Module server 啟動完所有的Server , 廣播本地module資訊給外人時後通知
	 */
	public void onModuleServerReadyStart() {
		return;
	}

	/**
	 * 各 module 之間網路連線建立之後觸發
	 */
	public void onServerConnectReady() 
	{
		return;
	}
	
	/**
	 * 處理收到同個 vm 下所有module同步資訊的消息
	 */
	public void onSyncInfos(SyncModuleInfosMessage message){
		//把共用設定套進module
		this.commonSettings = message.getCommonSettings();
		
		if(log.isInfoEnabled()){
			log.info("sync info done");
		}
		return;
	}

	/**
	 * 收到更新共用設定時，置換module內的共用設定
	 */
	public void onUpdateCommonSettings(CommonSettings commonSettings){
		this.commonSettings = commonSettings;
		if(log.isInfoEnabled()){
			log.info("update common settings complete!");
		}
		return;
	}
	
	/**
	 * 
	 */
	public void registerJmxInfo() {
		try {
			MBeanServer mbserver = ManagementFactory.getPlatformMBeanServer();
			jmxInfoName = new ObjectName("Modules:name=BasicServiceModule " + this.getModuleName());
			mbserver.registerMBean(this, jmxInfoName);
		} catch (Exception e) {
			log.error(e, e);
		}
	}

	/**
	 * 
	 */
	public void unregisterJmxInfo() {
		try {
			MBeanServer mbserver = ManagementFactory.getPlatformMBeanServer();
			if (mbserver != null) {
				mbserver.unregisterMBean(jmxInfoName);
			}
		} catch (Exception e) {
			log.error(e, e);
		}

	}

	/**
	 * 
	 */
	@Override
	public void sendTestRequest(String destModuleID) {
		serverTestLog += "1. Send Test Request To " + destModuleID + " : " + this.getModuleName() + " Time:"
				+ System.currentTimeMillis() + "\n";

		GroupMessage msg = new GroupMessage();
		msg.setDestModuleID(destModuleID);
		msg.setMessageType(MessageTypes.S_SERVER_TEST_REQUEST);
		msg.setMessageContent(this.getModuleName());
		MessageAction.sendMessage(msg);
	}

	@Override
	public String getServerTestLog() {
		return serverTestLog;
	}

	@Override
	public void setServerTestLog(String serverTestLog) {
		this.serverTestLog = serverTestLog;
	}

	/**
	 * 
	 * @param guid
	 * @param cmd
	 */
	protected void telnetString(TelGUID guid, String cmd) {
		STelnetCmdResult data = new STelnetCmdResult();
		data.guid = guid;
		data.moduleId = getModuleName();
		data.result = cmd;
		GroupMessage msg = new GroupMessage();
		msg.setMessageType(MessageTypes.TELNET_MANAGER);
		msg.setMessageContent(data);
		msg.setDestModuleID(null);
		MessageAction.sendGroupMessage(msg);
	}

	/**
	 * 
	 */
	public abstract void procTelnetCommand(STelnetCmd obj);

	/**
	 * 註冊群組module name
	 * game_info.propertes.group_xxx = module1,moudle2
	 */
	public void registerConsistentGroupName(String name) {
		if (consistentMap == null) {
			consistentMap = new ConcurrentHashMap<String, ConsistentHash<String>>();
		}

		try {
			String group = ServerProperties.getProperty("group_" + name);
			String[] glist = group.split(",");

			Set<String> node = new HashSet<String>();
			for (String n : glist) {
				node.add(n);
			}

			ConsistentHash<String> hash = new ConsistentHash<String>(160, node);
			consistentMap.put(name, hash);
		} catch (Exception e) {
			log.error(e, e);
		}
	}

	/**
	 * 讀取多個相同module時，分配至何module
	 * 
	 * @return
	 */
	public String lookUp(String groupname, GUID player) {
		if (!consistentMap.containsKey(groupname)) {
			return null;
		}

		ConsistentHash<String> look = consistentMap.get(groupname);
		return look.get(player.toString());
	}

	/**
	 * 註冊dc agent
	 * 
	 * @param c
	 */
	public void registerDCAgent(Class c) {
		if (dateCenterAgents == null) {
			dateCenterAgents = new ConcurrentHashMap<String, Object>();
		}

		try {
			DataManager dc = (DataManager) c.getConstructor(BasicServiceModule.class).newInstance(this);
			dateCenterAgents.put(c.getName(), dc);
		} catch (Exception e) {
			log.error(e, e);
		}
	}

	/**
	 * 讀取data center agent
	 * 
	 * @param name
	 * @return
	 */
	public DataManager getDCAgent(Class c) {
		if (dateCenterAgents == null || !dateCenterAgents.containsKey(c.getName())) {
			return null;
		}

		return (DataManager) dateCenterAgents.get(c.getName());
	}

	/**
	 * module 對應之processer實體
	 * 
	 * @return
	 */
	public BasiceServiceProcesser getBasicprocesser() {
		return basicprocesser;
	}

	public void setBasicprocesser(BasiceServiceProcesser proc) {
		basicprocesser = proc;
	}

	/**
	 * 遊戲log 寫入db
	 * @param gamelog
	 * {@link #twoStageWriteLog}
	 * {@link #BasicServiceModule()}
	 */
	public void saveDbLog(BasicLogModel gamelog) {
		if (twoStageWriteLog) { //使用兩階段寫入log
			GameWriteLogAsyncTask task = new GameWriteLogAsyncTask();
			task.gamelog = gamelog;
			task.setQueueID(GameUtility.getLastNIndex(asyncTaskQueueCount, 1));
			addAsyncCommand(task);
		} else { //直接寫入log
			Session session = HibernateLogManager.getLogSession();
			Transaction tx = session.getTransaction();
			tx.begin();
			session.save(gamelog);
			tx.commit();
			session.clear();
			HibernateLogManager.endSession();
		}
	}
	
	/**
	 * 收到 gmtool 廣播給所有 module, server 進入關機倒數狀態<br>
	 * @param notify
	 */
	public void onRecvServerShutdownCountdownNotify(SGmtoolServerShutdownCountdownNotify notify) 
	{
		return;
	}
	
	
	/**
	 * 收到 gmtool 廣播給所有 module, server 進入關機倒數狀態<br>
	 * 有需要收到通知的可以繼承改寫
	 * 
	 * @param notify
	 */
	public void onGameRecServerShutdownCountdownNotify(SGmtoolServerShutdownCountdownNotify notify)
	{
		this.state =ModuleState.WAIT_TO_CLOSE;
		this.shutdownType = notify.getShutdownType();
		onRecvServerShutdownCountdownNotify(notify);
		return;
	}
	

	/**
	 * 收到 gmtool 廣播給所有 module, server 進入踢玩家斷線狀態<br>
	 * 有需要收到通知的可以繼承改寫
	 */
	public void onRecvKickAllConnectionNotify(SGmtoolKickAllConnectionNotify request) {
		return;
	}
	
	/**
	*  收到 gmtool 廣播給所有 module, server 進入踢玩家斷線狀態<br>
	 * 有需要收到通知的可以繼承改寫
	 */
	public void onGameRecvKickAllConnectionNotify(SGmtoolKickAllConnectionNotify request)
	{	
		this.state = ModuleState.CLOSED;
		this.shutdownType = request.getShutdownType();
		onRecvKickAllConnectionNotify(request);
	}

	/**
	 * 收到 gmtool 廣播給所有 module, server 進入踢玩家斷線狀態<br>
	 * 有需要收到通知的可以繼承改寫
	 */
	public void onRecvStopTransactionNotify() {
		this.state = ModuleState.STOP_TRANSACTION;
	}
	
	/**
	 * 收到 gmtool 廣播給所有 module, server 現在進入的狀態<br>
	 * 有需要收到通知的可以繼承改寫
	 */
	public void onRecvChangeLevelNotify(int level){
		if(log.isInfoEnabled()){
			log.info("Now ChangeServerState From " + state + " to " + ModuleState.getModuleState(level).toString());
		}
		this.state = ModuleState.getModuleState(level);
		
		if (this.state == ModuleState.RUNNING || this.state == ModuleState.TestMode) { //2017-08-16 改成運行中，順便把關機模式改成無
			this.shutdownType = ServerShutdownType.NONE;
		}
	}
	
	/**
	 * 伺服器是否進入wait to close
	 * 
	 * @return
	 */
	public boolean isWaitToClose() {
		if (state.getLevel() >= ModuleState.WAIT_TO_CLOSE.getLevel()) {
			return true;
		}

		return false;
	}
	
	/**
	 * 是否在禁止交易行為模式
	 * 
	 * @return
	 */
	public boolean isStopTransaction() {
		if (state.getLevel() >= ModuleState.STOP_TRANSACTION.getLevel()) {
			return true;
		}

		return false;
	}
	
	/**
	 * 是否正在測試模式
	 * 
	 * @return
	 */
	public boolean isTestMode(){
		if(state.getLevel() == ModuleState.TestMode.getLevel()){
			return true;
		}
		return false;
	}
	
	/**
	 * 是否正在運行中模式
	 * @return
	 */
	public boolean isRunning(){
		if(state.getLevel() == ModuleState.RUNNING.getLevel()){
			return true;
		}
		return false;
	}
	
	/**
	 * 是否是單一維護
	 * @return
	 */
	public boolean isSingleGameMaintain(){
		if(this.shutdownType == ServerShutdownType.Single_Game){
			return true;
		}
		return false;
	}
	
	/**
	 * 是否是全部遊戲維護
	 * @return
	 */
	public boolean isAllGameMaintain() {
		if (this.shutdownType == ServerShutdownType.All_Game) {
			return true;
		}
		return false;
	}
	
	@Override
	public void procThrowException(Object obj) 
	{
		NetMessage message = null;
		if(obj instanceof NetMessage)
		{
			message = (NetMessage) obj;
		}
		else
		{
			return;
		}
		
		MoudleProcessErrorResponse response = new MoudleProcessErrorResponse();
		response.setMessagetype(message.getMessageType());
		MessageAction.sendMessage(message.getSessionID() , MessageTypes.MSG_PROCESS_ERROR, response);
	}
	
	

	/**
	 * 角色登入遊戲中的通知
	 * 
	 * @param notify
	 */
	public void onPlayerLoginGameNotify(SCharacterLoginNotify notify) {
	}
	
		/**
	 * CronTaskTimer
	 * 判斷 是不是有沒有做的行程
	 * @param taskTimer
	 * @param cronExpression
	 */
	public ArrayList<Long> checkCronTaskTimerSchedule(CronTaskTimer taskTimer){
		return CronJobDAO.determinedSchedule(taskTimer);
	}
	
	
	/**
	 * CronTaskTimer
	 * 完成後建立新的行程
	 */
	public void addCronTaskTimerNewSchedule(CronTaskTimer taskTimer){
		CreateNewScheduleAsync async = new CreateNewScheduleAsync();
		async.cronTaskTimer = taskTimer;
		addAsyncCommand(async);
	}
	
	/**
	 * 判斷自己這個module是不是第一個module
	 */
	public boolean isFirstModule() {
		//自己的moduleName
		String moduleName = this.getModuleName();
		//取得所有的moduleName
		HashMap<String, List<String>> modules = ServerProperties.getModules();
		
		if(modules == null || modules.size() == 0){
			if(log.isErrorEnabled()){
				log.error(GameUtility.getCurMethodName()+" there is no module in game_info.properties");
			}
			return false;
		}

		//對每個server搜尋
		for(List<String> moduleList : modules.values()){
			if(moduleList.contains(moduleName)){
				//用"_"分割
				 String[] check = moduleName.split("_");
				//如果分割完只有一個元素，表示自己就是第一個
				if(check.length == 1){
					return true;
				}
				//如果分割完有兩個元素，應該是group module，檢查第二個元素
				else if(check.length == 2){
					//group的 moduleName處理
					try {
						int number = Integer.valueOf(check[1]);
						if(number == 1)
							return true;
						else
							return false;
					}
					//如果check[1]不能被轉成數字就回傳false
					catch (Exception e) {
						if(log.isErrorEnabled()){
							log.error(GameUtility.getCurMethodName()+" group moduleName's number is not integer, moduleName: "+moduleName);
						}
						return false;
					}
				}
				//正常的命名分割完會有一個或兩個元素，其他的都視為不認識，回傳false
				else{
					if(log.isErrorEnabled()){
						log.error(GameUtility.getCurMethodName()+" can't recognize moduleName: "+moduleName);
					}
					return false;
				}

			}//if(moduleList.contains(moduleName)){
			
		}//for搜尋結束
		
		//game_info.properties裡面找不到這個moduleName
		if(log.isErrorEnabled()){
			log.error(GameUtility.getCurMethodName()+" can't find moduleName in game_info.properties, moduleName: "+moduleName);
		}
		return false;
	}

	public AtomicInteger getTaskCounter() {
		return taskCounter;
	}
}
